﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace OEMS
{
    /// <summary>
    /// Code achter het ColorPaletteDialogForm, deze code zorgt voor een simpele kleurkiezer.
    /// </summary>
    /// <author>Mathieu Cruts</author>
    public partial class ColorPaletteDialogForm : Form
    {
        private Color selectedColor;
        private Panel[] panel;
        private List<Color> colors = new List<Color>();


        #region CONSTRUCTOR
        /// <summary>
        /// Constructor die zorgt dat onze kleurkiezer net onder de button wordt weergegeven
        /// </summary>
        /// <param name="x">x-coordinaat om te beginnen tekenen</param>
        /// <param name="y">y-coordinaat om te beginnen tekenen</param>
        /// <author>Mathieu Cruts</author>
        public ColorPaletteDialogForm(int x, int y)
        {
            InitializeComponent();

            this.Location = new Point(x, y);

            colors = GetColors();
            
            // Maakt evenveel panels aan als kleuren
            panel = new Panel[colors.Count];

            BuildPalette();
        }
        #endregion


        #region BUILDDATA
        /// <summary>
        /// Haalt een lijst van kleuren op die herkend worden door .NET (de grafiek zou niet werken met hexadecimale kleurwaardes)
        /// </summary>
        /// <returns>de lijst met kleuren</returns>
        /// <author>Mathieu Cruts</author>
        private List<Color> GetColors()
        {
            List<Color> colors = new List<Color>();
            List<String> kleuren = new List<string>();
            String[] colorNames = Enum.GetNames(typeof(KnownColor)); // enumeratie van de namen van kleuren van het type "KnownColors"
            Boolean add = true;


            foreach (string colorName in colorNames)
            {
                // Zet de gekende kleurnaam om in de effectieve kleur
                KnownColor knownColor = (KnownColor)Enum.Parse(typeof(KnownColor), colorName);

                // Kijkt na of de huidige kleurnaam geldig is voor de grafiek of niet
                add = checkForFiltering(colorName);

                if (add)
                {
                    colors.Add(Color.FromName(colorName));
                    kleuren.Add(colorName);
                }

            }

            colors = sortColors(colors);
            return colors;
        }


        /// <summary>
        /// Methode die de colorpicker visueel opbouwt
        /// </summary>
        /// <author>Mathieu Cruts</author>
        private void BuildPalette()
        {
            Color white = Color.White;

            int width = 20;
            int height = 20;
            int distance = 4;
            int border = 5;

            int x = border;
            int y = border;

            ToolTip toolTip = new ToolTip();


            for (int i = 0; i < panel.Length; i++)
            {
                panel[i] = new Panel();

                panel[i].Height = width;
                panel[i].Width = height;
                panel[i].Location = new Point(x, y);

                // Laat in een tooltip de kleurnaam zien als de gebruiker er over scrollt
                toolTip.SetToolTip(panel[i], colors[i].Name);

                this.Controls.Add(panel[i]);

                // Kijkt na wanneer een nieuwe rij moet ingevoegd worden
                if (x < (7 * (width + distance)))
                    x += width + distance;
                else
                {
                    x = border;
                    y += height + distance;
                }

                panel[i].BackColor = colors[i];
                panel[i].MouseUp += new MouseEventHandler(OnMouseUpPanel);
            }
        }
        #endregion


        #region FILTER AND SORT COLORS
        /// <summary>
        /// Filtert de lijst van kleuren:
        /// Donkere, lichte en medium tinten worden verwijderd
        /// Menu en buttonkleuren worden verwijderd
        /// Zilver en gradients worden verwijderd
        /// Te lichte kleuren worden verwijderd
        /// </summary>
        /// <param name="colorName">de kleurnaam om na te kijken</param>
        /// <returns>booleaanse waarde of de kleur mag toegevoegd worden of niet</returns>
        /// <author>Mathieu Cruts</author>
        private Boolean checkForFiltering(String colorName)
        {
            Color color = Color.FromName(colorName);
            colorName = colorName.ToLower();
            Boolean add = true;

            if (colorName.StartsWith("dark") || colorName.StartsWith("light") || colorName.StartsWith("medium")
                || colorName.StartsWith("button") || colorName.StartsWith("gradient") || colorName.StartsWith("menu") || colorName.Equals("silver"))
            {
                add = false;
            }

            // Filtert nog een aantal te lichte kleuren
            else if ((color.R + color.G + color.B) >= 600)
            {
                add = false;
            }

            return add;

        }


        /// <summary>
        /// Sorteert de kleuren zo goed mogelijk
        /// </summary>
        /// <param name="colors">de lijst met kleuren die gesorteerd zullen worden</param>
        /// <returns>lijst met de gesorteerde kleuren</returns>
        /// <author>Mathieu Cruts</author>
        private List<Color> sortColors(List<Color> colors)
        {
            List<Color> blackGrayWhite = new List<Color> {Color.Black, Color.Gray, Color.White};
            List<Color> mostRed = new List<Color>();
            List<Color> mostGreen = new List<Color>();
            List<Color> mostBlue = new List<Color>();
            List<Color> others = new List<Color>();
            List<Color> sortedList = new List<Color>();


            foreach (Color color in colors)
            {
                // Hoogste waarde rood
                if (color.R > color.G && color.R > color.B)
                {
                    mostRed.Add(color);
                }
                // Hoogste waarde groen
                else if (color.G > color.R && color.G > color.B)
                {
                    mostGreen.Add(color);
                }
                // Hoogste waarde blauw
                else if (color.B > color.R && color.B > color.G)
                {
                    mostBlue.Add(color);
                }
                else
                {
                    others.Add(color);
                }
            }

            // Sorteert de kleuren nog eens extra op helderheid
            sortByBrightness(mostBlue);
            sortByBrightness(mostRed);
            sortByBrightness(mostGreen);

            // Voeg zwart, grijs, wit en onze gesorteerde kleurenlijsten toe aan de totaallijst
            sortedList.AddRange(blackGrayWhite);
            sortedList.AddRange(mostBlue);
            sortedList.AddRange(mostRed);
            sortedList.AddRange(mostGreen);

            return sortedList;

        }


        /// <summary>
        /// Sorteert de kleuren op helderheid
        /// </summary>
        /// <param name="colors">de lijst met kleuren die gesorteerd zullen worden</param>
        /// <returns>lijst met de gesorteerde kleuren</returns>
        /// <author>found on bytes.com</author>
        private List <Color> sortByBrightness(List <Color> colors)
        {
            colors.Sort(delegate(System.Drawing.Color left, System.Drawing.Color right)
            {
                return left.GetBrightness().CompareTo(right.GetBrightness());
            });

            return colors;
        }
        #endregion


        #region HANDLERS
        /// <summary>
        /// Handelt de gekozen kleur af als de gebruiker geklikt heeft en terug loslaat
        /// </summary>
        /// <author>Mathieu Cruts</author>
        private void OnMouseUpPanel(Object sender, MouseEventArgs e)
        {
            Panel panel = (Panel)sender;

            selectedColor = panel.BackColor;
            DialogResult = DialogResult.OK;

            this.Close();
        }


        /// <summary>
        /// Sluit ons colorpicker venster
        /// </summary>
        /// <author>Mathieu Cruts</author>
        private void returnButton_Click(object sender, EventArgs e)
        {
            this.Close();
        }
        #endregion


        #region GETTERS
        /// <summary>
        /// Getter van de geselecteerde kleur
        /// </summary>
        /// <author>Mathieu Cruts</author>
        public Color Color
        {
            get { return selectedColor; }
        }
        #endregion

    }
}
